/*=============================================================================

    Copyright (c) Pascal Gilcher. All rights reserved.

 * Unauthorized copying of this file, via any medium is strictly prohibited
 * Proprietary and confidential

=============================================================================*/

#pragma once

/*===========================================================================*/

namespace Denoise
{

struct FilterSample
{
    float4 gbuffer;
    float4 val;
};

FilterSample fetch_sample(in float2 uv, sampler gi)
{
    FilterSample o;
    o.gbuffer = tex2Dlod(sGBufferTex, uv, 0);
    o.val     = tex2Dlod(gi, uv, 0);
    return o;
}

float3 unpack_hdr(float3 color)
{
    color  = saturate(color);
    //color *= color;
    color = color * rcp(1.04 - saturate(color));   
    return color;
}

float3 pack_hdr(float3 color)
{
    color =  1.04 * color * rcp(color + 1.0);
    color  = saturate(color);
    //color = sqrt(color);   
    return color;     
}

float4 atrous(in VSOUT i, in sampler gi, int iteration, int mode)
{
    FilterSample center = fetch_sample(i.uv, gi);

    if(mode < 0) //skip
        return center.val;    

    float4 value_sum = center.val * 0.01; 
    float4 weight_sum = 0.01; 

    float4 kernel = float4(1.5,3.5,7,15);
    float4 sigma_z = float4(0.7,0.7,0.7,0.7);
    float4 sigma_n = float4(0.75,1.5,1.5,5);
    float4 sigma_v = float4(0.035,0.6,1.4,5);

    if(mode == 1)
    {
        sigma_z *= 4;
        sigma_n *= 10;
        sigma_v *= 64;      
    }

    float expectederror = sqrt(RT_RAY_AMOUNT);
  
    for(float x = -1; x <= 1; x++)
    for(float y = -1; y <= 1; y++)
    {        
        float2 uv = i.uv + float2(x, y) * kernel[iteration] * BUFFER_PIXEL_SIZE;
        FilterSample tap = fetch_sample(uv, gi);

        float wz = sigma_z[iteration] * 16.0 *  (1.0 - tap.gbuffer.w / center.gbuffer.w);
        wz = saturate(0.5 - lerp(wz, abs(wz), 0.75));

        float wn = saturate(dot(tap.gbuffer.xyz, center.gbuffer.xyz) * (sigma_n[iteration] + 1) - sigma_n[iteration]);
        wn = lerp(wn, 1, saturate(wz * 1.42 - 0.42));

        float4 wi;
        wi.rgb = dot(abs(pack_hdr(tap.val.rgb) - pack_hdr(center.val.rgb)), float3(0.3, 0.59, 0.11));
        wi.w = abs(tap.val.w - center.val.w);
        wi = rcp(1 + wi * wi * float4(20, 20, 20, 180) * sigma_v[iteration] * expectederror); 
        
        float4 w = saturate(wz * wn * wi);

        value_sum += tap.val * w;
        weight_sum += w;
    }

    float4 result = value_sum / weight_sum;
    return result;
}

} //Namespace